﻿#include "hzpch.h"
#include "OpenGLVertexArray.h"

#include <glad/glad.h>

namespace Hazal
{
	static GLenum ShaderDataTypeToOpenGLBaseType(EShaderDataType eType)
	{
		switch (eType)
		{
		case EShaderDataType::None:     return GL_NONE;
		case EShaderDataType::Float:    return GL_FLOAT;
		case EShaderDataType::Float2:   return GL_FLOAT;
		case EShaderDataType::Float3:   return GL_FLOAT;
		case EShaderDataType::Float4:   return GL_FLOAT;
		case EShaderDataType::Mat3:		return GL_FLOAT;
		case EShaderDataType::Mat4:		return GL_FLOAT;
		case EShaderDataType::Int:		return GL_INT;
		case EShaderDataType::Int2:		return GL_INT;
		case EShaderDataType::Int3:		return GL_INT;
		case EShaderDataType::Int4:		return GL_INT;
		case EShaderDataType::Bool:		return GL_INT;
		}

		HZ_ASSERT(false, "Unknown ShaderDataType!")
			return GL_NONE;
	}

	COpenGLVertexArray::COpenGLVertexArray()
		:m_unRendererID(0)
	{
		glCreateVertexArrays(1, &m_unRendererID);
	}

	COpenGLVertexArray::~COpenGLVertexArray()
	{
		glDeleteVertexArrays(1, &m_unRendererID);
	}

	void COpenGLVertexArray::Bind() const
	{
		glBindVertexArray(m_unRendererID);
	}

	void COpenGLVertexArray::Unbind() const
	{
		glBindVertexArray(0);
	}

	void COpenGLVertexArray::AddVertexBuffer(const Ref<CVertexBuffer>& rVertexBuffer)
	{
		HZ_ASSERT(rVertexBuffer->GetLayout().GetElements().size(), "Current vertex buffer has no layout!");

		glBindVertexArray(m_unRendererID);
		rVertexBuffer->Bind();

		uint32_t unIdx = 0;
		const CBufferLayout& layout = rVertexBuffer->GetLayout();
		for (const auto& element : layout)
		{
			glEnableVertexAttribArray(unIdx);


			switch (element.m_eType)
			{
			case EShaderDataType::Int:
			case EShaderDataType::Int2:
			case EShaderDataType::Int3:
			case EShaderDataType::Int4:
			{
				glVertexAttribIPointer(unIdx, element.GetComponentCount(),
					ShaderDataTypeToOpenGLBaseType(element.m_eType),
					layout.GetStride(),
					(const void*)element.m_unOffset);
				break;
			}
			case EShaderDataType::Float:
			case EShaderDataType::Float2:
			case EShaderDataType::Float3:
			case EShaderDataType::Float4:
			{
				glVertexAttribPointer(unIdx, element.GetComponentCount(),
					ShaderDataTypeToOpenGLBaseType(element.m_eType),
					element.m_bNormalized ? GL_TRUE : GL_FALSE,
					layout.GetStride(),
					(const void*)element.m_unOffset);
				break;
			}
			default:
				break;
			}

			++unIdx;
		}

		m_vertexBuffers.push_back(rVertexBuffer);
	}

	void COpenGLVertexArray::SetIndexBuffer(const Ref<CIndexBuffer>& rIndexBuffer)
	{
		glBindVertexArray(m_unRendererID);
		rIndexBuffer->Bind();

		m_indexBuffer = rIndexBuffer;
	}
	const std::vector<Ref<CVertexBuffer>>& COpenGLVertexArray::GetVertexBuffers() const
	{
		return m_vertexBuffers;
	}
	const Ref<CIndexBuffer>& COpenGLVertexArray::GetIndexBuffer() const
	{
		return m_indexBuffer;
	}
}